iT邦幫忙

2023 iThome 鐵人賽

DAY 18
0
Modern Web

30 天淺入淺出 Next.js 13系列 第 18

Day 18 - Error Handling 捕捉網頁發生的錯誤

  • 分享至 

  • xImage
  •  

前言

網頁在運行的時候,難免會拋出錯誤。當我們沒有做任何錯誤處理時,網頁有任何錯誤拋出就會卡住不動,最慘的狀況就是網頁一片空白,使用者也不知道發生什麼事。

這時我們就需要捕捉網頁中的錯誤,並且根據錯誤回饋給使用者一個錯誤頁面。最好要有一個「重新整理」的按鈕,讓使用者可以不用真的按下 F5 來重整網頁,畢竟按下 F5 重新整理 js 的暫存記憶體都會清空,畫面也要重新請求,這樣 cost 會比較大。

接下來會講到 Next 如何實作錯誤處理以及背後的實作方式。

大綱

  • Error Handling
    • 建立 error handling
    • error handling 結構
    • error handling 用法
    • global error handling
  • React Error Handling

Error Handling

app router 裡可以建立 error component,這時 Next 會自動建立一個 error boundary 來捕捉 page component 拋出的任何 error,如果捕捉到錯誤就會顯示 error 的 UI。

建立 error handling

  • 建立 error component
  • export client component
'use client' // error 一定要是 client component
 
import { useEffect } from 'react'
 
export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  useEffect(() => {
    // log 錯誤訊息
    console.error(error)
  }, [error])
 
  return (
    <div>
      <h2>Something went wrong!</h2>
      <button
        onClick={
          // 重新整理
          () => reset()
        }
      >
        Try again
      </button>
    </div>
  )
}

error handling 結構

在同一個 folder 中建立的 error 只會包住 page,只有 page 拋出錯誤時才會捕捉到。其他像是 layouttemplate 這些共用 UI 並不會包含進去,原因是路由切換時這些共用 UI 不太會發生錯誤。

每個 folder 都可以建立自己的 error handling,當路由嵌套時就會有多個 error 互相嵌套。

若 child page 拋出錯誤時,它會優先被離他最近的 child folder 建立的 error 所捕捉,這也很好理解,畢竟近水樓臺先得月

底下 /dashboard 這個 route 拋出的錯誤會優先被 dashboard 這個資料夾的 error 所捕捉,若 dashboard 沒有建立 error,才會往上被根目錄的 error 捕捉。

error handling 用法

  1. error 必須是 client component。
  2. error 的 props 可以解構出兩個參數:error 和 reset。

props 解構出來的 error 就是子組件拋出的錯誤資訊,可以根據錯誤內容顯示不同的 UI。

reset 則是一個 function,執行後會重新 re-render page component,而不需要重新整理網頁。

global-error handling

上面講到 error 並不會捕捉到同一層 layouttemplate 的錯誤,如果需要捕捉共用組件的 UI,就必須在更上一層建立一個 error 來捕捉子層共用 UI 拋出的錯誤。

這樣一直追上去就會發生一個問題,就是沒辦法幫根目錄的 layout 與 template 建立 error handling

這就是 global-error 誕生的其中一個目的,global-error 包住了整個 web app,也是整個 web app 的最後一道防線,這裡沒捕捉到錯誤那網頁就等著卡住了。

與一般 error 的寫法不同,有幾個需要注意的地方:

  1. 在根目錄建立 global-error 這個檔案
  2. global-error 必須定義 <html><body>

這樣我們就可以為整個 web app 加上最後一道保障。

  • 建立 global-error component
  • export 包含 <html><body> 的 client component
'use client'
 
export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <html>
      <body>
        <h2>Something went wrong!</h2>
        <button onClick={() => reset()}>Try again</button>
      </body>
    </html>
  )
}

React Error Handling

Next 使用的 Error Handling 就是 React 本身常見的 error boundary 的作法。

它是使用 react class component 的寫法,捕捉 children 拋出的錯誤,並且返回 fallback props 的 UI。

有興趣的人可以看看 React 官網的文章

後記

寫鐵人賽的同時邊 loop 這首 guitar solo,jam 的超好聽 OwO

他還在 2022 年用同一個 beats 再 jam 了一次,也超級好聽,建議晚上不要聽,不然會 loop 到天亮。

歌曲連結

參考資料


上一篇
Day 17 - Streaming 為你的 web vitals 加分
下一篇
Day 19 - Parallel Routes 路由的平行宇宙
系列文
30 天淺入淺出 Next.js 1321
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言